home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / sat / msat09.tgz / XTLM.C < prev    next >
Text File  |  1994-09-17  |  20KB  |  945 lines

  1. /*
  2.  *   Copyright 1992, 1993, 1994 John Melton (G0ORX/N6LYT)
  3.  *              All Rights Reserved
  4.  *
  5.  *   This program is free software; you can redistribute it and/or modify
  6.  *   it under the terms of the GNU General Public License as published by
  7.  *   the Free Software Foundation; either version 1, or (at your option)
  8.  *   any later version.
  9.  *
  10.  *   This program is distributed in the hope that it will be useful,
  11.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *   GNU General Public License for more details.
  14.  *
  15.  *   You should have received a copy of the GNU General Public License
  16.  *   along with this program; if not, write to the Free Software
  17.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20.  
  21. /*
  22.     xtlm.c
  23.  
  24.     telemery decoding program for PACSATs
  25.     
  26.      -           -      -
  27.  
  28.     This software was written to provide a receive only capability
  29.     for collecting files and directories from satellites running
  30.     the Pacsat Protocols running on the Linux Operating System.
  31.  
  32.     This program has been run using the 1.0 version of the
  33.     Linux kernel with the patches from Alan Cox to provide AX.25
  34.     encapsulation of SLIP.
  35.  
  36.     The TNC must be setup for KISS.
  37.  
  38.     John Melton
  39.     G0ORX, N6LYT
  40.  
  41.     4 Charlwoods Close
  42.     Copthorne
  43.     West Sussex
  44.     RH10 3QZ
  45.     England
  46.  
  47.     INTERNET:    g0orx@amsat.org
  48.             n6lyt@amsat.org
  49.             john@images.demon.co.uk
  50.             J.D.Melton@slh0613.icl.wins.co.uk
  51.  
  52.     History:
  53.     -------
  54.  
  55.     0.1    Initial version                G4KLX
  56. */
  57.  
  58. #define VERSION_STRING "(version 0.1 by g4klx)"
  59.  
  60. #include <X11/Intrinsic.h>
  61. #include <X11/StringDefs.h>
  62. #include <X11/Shell.h>
  63. #include <X11/Xaw/Cardinals.h>
  64. #include <X11/Xaw/Command.h>
  65. #include <X11/Xaw/Label.h>
  66. #include <X11/Xaw/Viewport.h>
  67.  
  68. #include <sys/types.h>
  69. #include <sys/socket.h>
  70.  
  71. #include <netinet/in.h>
  72. #include <linux/ax25.h>
  73.  
  74. #include <fcntl.h>
  75. #include <unistd.h>
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <signal.h>
  79. #include <ctype.h>
  80. #include <time.h>
  81.  
  82. #include "crc.h"
  83.  
  84. Display *dpy;
  85.  
  86. XtAppContext app_context;
  87.  
  88. typedef struct
  89. {
  90.     XFontStruct *button_font, *text_font;
  91. }
  92. Resources;
  93.  
  94. Resources  resources;
  95.  
  96. Widget toplevel, compwindow, quitbutton, lognextbutton, button[10], viewport,
  97.     pagelabel, timelabel, tlmlabel, crclabel, form, label[23];
  98.  
  99. XtResource resource_list[] =
  100. {
  101.     {"buttonFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  102.         XtOffsetOf(Resources, button_font), XtRString, XtDefaultFont},
  103.     {"textFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  104.         XtOffsetOf(Resources, text_font), XtRString, XtDefaultFont}
  105. };
  106.  
  107. Arg shell_args[] =
  108. {
  109.     {XtNtitle,        (XtArgVal)NULL}
  110. };
  111.  
  112. Arg form_args[] =
  113. {
  114.     {XtNdefaultDistance,    (XtArgVal)0}
  115. };
  116.  
  117. Arg button_args[] =
  118. {
  119.     {XtNcallback,        (XtArgVal)NULL},
  120.     {XtNlabel,        (XtArgVal)NULL},
  121.     {XtNfromHoriz,        (XtArgVal)NULL},
  122.     {XtNfont,        (XtArgVal)NULL},
  123.     {XtNresize,        (XtArgVal)False},
  124.     {XtNvertDistance,    (XtArgVal)6},
  125.     {XtNhorizDistance,    (XtArgVal)8},
  126.     {XtNtop,        XtChainTop},
  127.     {XtNbottom,        XtChainTop},
  128.     {XtNleft,        XtChainLeft},
  129.     {XtNright,        XtChainLeft}
  130. };
  131.  
  132. Arg title_args[] =
  133. {
  134.     {XtNfromVert,        (XtArgVal)NULL},
  135.     {XtNfromHoriz,        (XtArgVal)NULL},
  136.     {XtNfont,        (XtArgVal)NULL},
  137.     {XtNwidth,        (XtArgVal)70},
  138.     {XtNvertDistance,    (XtArgVal)0},
  139.     {XtNhorizDistance,    (XtArgVal)5},
  140.     {XtNlabel,        (XtArgVal)""},
  141.     {XtNheight,        (XtArgVal)25},
  142.     {XtNresize,        False},
  143.     {XtNborderWidth,    (XtArgVal)0},
  144.     {XtNjustify,        XtJustifyLeft},
  145.     {XtNtop,        XtChainTop},
  146.     {XtNbottom,        XtChainTop},
  147.     {XtNleft,        XtChainLeft},
  148.     {XtNright,        XtChainRight}
  149. };
  150.  
  151. Arg label_args[] =
  152. {
  153.     {XtNfromVert,        (XtArgVal)NULL},
  154.     {XtNfont,        (XtArgVal)NULL},
  155.     {XtNvertDistance,    (XtArgVal)6},
  156.     {XtNhorizDistance,    (XtArgVal)8},
  157.     {XtNwidth,        (XtArgVal)550},
  158.     {XtNlabel,        (XtArgVal)""},
  159.     {XtNborderWidth,    (XtArgVal)0},
  160.     {XtNheight,        (XtArgVal)15},
  161.     {XtNresize,        False},
  162.     {XtNjustify,        XtJustifyLeft},
  163.     {XtNtop,        XtChainTop},
  164.     {XtNbottom,        XtChainTop},
  165.     {XtNleft,        XtChainLeft},
  166.     {XtNright,        XtChainLeft}
  167. };
  168.  
  169. Arg viewport_args[] =
  170. {
  171.     {XtNfromVert,        (XtArgVal)NULL},
  172.     {XtNwidth,        (XtArgVal)600},
  173.     {XtNheight,        (XtArgVal)300},
  174.     {XtNallowVert,        True},
  175.     {XtNforceBars,        True},
  176.     {XtNresize,        True},
  177.     {XtNvertDistance,    (XtArgVal)0},
  178.     {XtNhorizDistance,    (XtArgVal)0},
  179.     {XtNtop,        XtChainTop},
  180.     {XtNbottom,        XtChainBottom},
  181.     {XtNleft,        XtChainLeft},
  182.     {XtNright,        XtChainRight}
  183. };
  184.  
  185. #define    PID_TEXT    0xF0
  186. #define    MAXBUFFER    300
  187.  
  188. #define    ONLINE_MODE    0
  189. #define    FILE_MODE    1
  190.  
  191. int mode = ONLINE_MODE;
  192.  
  193. char satelliteId[16];
  194.  
  195. int current_page = 0;
  196. int tlmBytes     = 0;
  197. int crcErrors    = 0;
  198. time_t timestamp = 0;
  199.  
  200. int s_raw = 0;
  201.  
  202. FILE *fpraw = NULL;
  203.  
  204. struct equation
  205. {
  206.     struct equation *next;        /* A D S */
  207.     char type;            /* A D S */
  208.     int  channel;            /* A D S */
  209.     char *title;            /* A D S */
  210.     int  value;            /* A D S */
  211.     int  page, row, column;        /* A D S */
  212.     int  occurence;            /* A     */
  213.     double a, b, c;            /* A     */
  214.     int  status;            /*   D   */
  215.     char *state0, *state1;        /*     S */
  216. };
  217.  
  218. struct equation *first = NULL;
  219.  
  220. /*
  221.  *    Convert a call from the shifted ascii form used in an
  222.  *    AX.25 packet.
  223.  */
  224. int ConvertCall(char *c, char *call)
  225. {
  226.     char *ep = c + 6;
  227.     int ct = 0;
  228.  
  229.     while (ct < 6)
  230.     {
  231.         if (((*c >> 1) & 127) == ' ') break;
  232.  
  233.         *call = (*c >> 1) & 127;
  234.         call++;
  235.         ct++;
  236.         c++;
  237.     }
  238.     
  239.     if ((*ep & 0x1E) != 0)
  240.     {    
  241.         *call = '-';
  242.         call++;
  243.         call += sprintf(call, "%d", (int)(((*ep) >> 1) & 0x0F));
  244.     }
  245.  
  246.     *call = '\0';
  247.     
  248.     if (*ep & 1) return 0;
  249.  
  250.     return 1;
  251. }
  252.  
  253. void UpdateStatus(void)
  254. {
  255.     static int lastPage    = -1;
  256.     static time_t lastTime = -1;
  257.     static int lastTLM     = -1;
  258.     static int lastCRC     = -1;
  259.     char label[40], *s;
  260.     Arg args[1];
  261.  
  262.     if (lastPage != current_page)
  263.     {
  264.         sprintf(label, "Page %2d", current_page);
  265.  
  266.         XtSetArg(args[0], XtNlabel, label);
  267.         XtSetValues(pagelabel, args, ONE);
  268.  
  269.         lastPage = current_page;
  270.     }
  271.  
  272.     if (lastTime != timestamp)
  273.     {
  274.         s = ctime(×tamp);
  275.         s[24] = '\0';
  276.  
  277.         sprintf(label, "Timestamp %s", s);
  278.  
  279.         XtSetArg(args[0], XtNlabel, label);
  280.         XtSetValues(timelabel, args, ONE);
  281.  
  282.         lastTime = timestamp;
  283.     }
  284.  
  285.     if (lastTLM != tlmBytes)
  286.     {
  287.         sprintf(label, "TLM bytes %5d", tlmBytes);
  288.  
  289.         XtSetArg(args[0], XtNlabel, label);
  290.         XtSetValues(tlmlabel, args, ONE);
  291.  
  292.         lastTLM = tlmBytes;
  293.     }
  294.  
  295.     if (lastCRC != crcErrors)
  296.     {
  297.         sprintf(label, "CRC errors %3d", crcErrors);
  298.  
  299.         XtSetArg(args[0], XtNlabel, label);
  300.         XtSetValues(crclabel, args, ONE);
  301.  
  302.         lastCRC = crcErrors;
  303.     }
  304. }
  305.  
  306. void DisplayBinary(char *s, int value)
  307. {
  308.     int i;
  309.  
  310.     *s = '\0';
  311.     
  312.     for (i = 0; i < 12; i++)
  313.     {
  314.         if (value & (0x800 >> i))
  315.             strcat(s, "1");
  316.         else
  317.             strcat(s, "0");
  318.     }
  319. }
  320.  
  321. void DrawTLMPage(int page)
  322. {
  323.     struct equation *equation;
  324.     char *buffer[23], *title, data[15];
  325.     Arg args[1];
  326.     double result;
  327.     int i, row, column, offset, value;
  328.  
  329.     current_page = page;
  330.  
  331.     for (i = 0; i < 23; i++)
  332.     {
  333.         buffer[i] = XtMalloc(85);
  334.         memset(buffer[i], ' ', 84);
  335.         buffer[i][84] = '\0';
  336.     }
  337.  
  338.     equation = first;
  339.  
  340.     while (equation != NULL)
  341.     {
  342.         if (equation->page == page)
  343.         {
  344.             title  = equation->title;
  345.             column = equation->column;
  346.             row    = equation->row;
  347.             value  = equation->value;
  348.         
  349.             switch (equation->type)
  350.             {
  351.                 case 'A':
  352.                     offset = column * 27;
  353.                     strncpy(buffer[row] + offset, title, strlen(title));
  354.                     if (value != -1)
  355.                     {
  356.                         result = equation->a * (double)value * (double)value +
  357.                              equation->b * (double)value +
  358.                              equation->c;
  359.                         sprintf(data, "%.2f", result);
  360.                         strncpy(buffer[row] + offset + 25 - strlen(data), data, strlen(data));
  361.                     }
  362.                     break;
  363.                 case 'D':
  364.                     offset = column * 27;
  365.                     strncpy(buffer[row] + offset, title, strlen(title));
  366.                     if (value != -1)
  367.                     {
  368.                         DisplayBinary(data, value);
  369.                         strncpy(buffer[row] + offset + 25 - strlen(data), data, strlen(data));
  370.                     }
  371.                     break;
  372.                 case 'S':
  373.                     offset = column * 42;
  374.                     strncpy(buffer[row] + offset, title, strlen(title));
  375.                     if (value != -1)
  376.                     {
  377.                         if (value)
  378.                             strncpy(buffer[row] + offset + 30, equation->state1, strlen(equation->state1));
  379.                         else
  380.                             strncpy(buffer[row] + offset + 30, equation->state0, strlen(equation->state0));
  381.                     }
  382.                     break;
  383.                 default:
  384.                     break;
  385.             }
  386.         }
  387.  
  388.         equation = equation->next;
  389.     }
  390.  
  391.     for (i = 0; i < 23; i++)
  392.     {
  393.         XtSetArg(args[0], XtNlabel, buffer[i]);
  394.         XtSetValues(label[i], args, ONE);
  395.         XtFree(buffer[i]);
  396.     }
  397. }
  398.  
  399. void FillStates(int status, int value)
  400. {
  401.     struct equation *equation;
  402.     int i, channel, bit;
  403.  
  404.     for (i = 0; i < 12; i++)
  405.     {
  406.         channel = status + i;
  407.         bit     = value & (0x800 >> i);
  408.  
  409.         equation = first;
  410.     
  411.         while (equation != NULL)
  412.         {
  413.             if (equation->channel == channel &&
  414.                 equation->type    == 'S')
  415.                 equation->value = (bit != 0);
  416.  
  417.             equation = equation->next;
  418.         }
  419.     }
  420. }
  421.  
  422.  
  423. void FillTLM(int value, int channel, int occurence)
  424. {
  425.     struct equation *equation;
  426.     
  427.     equation = first;
  428.     
  429.     while (equation != NULL)
  430.     {
  431.         if (equation->channel   == channel   &&
  432.             equation->occurence == occurence &&
  433.            (equation->type      == 'A'       ||
  434.             equation->type      == 'D'))
  435.         {
  436.             switch (equation->type)
  437.             {
  438.                 case 'A':
  439.                     equation->value = value;
  440.                     break;
  441.                 case 'D':
  442.                     equation->value = value;
  443.                     FillStates(equation->status, equation->value);
  444.                     break;
  445.                 default:
  446.                     break;
  447.             }
  448.             
  449.             return;
  450.         }
  451.     
  452.         equation = equation->next;
  453.     }
  454. }
  455.  
  456. void DecodeTLM(unsigned char *buffer, int bufsize)
  457. {
  458.     int i;
  459.     int type, value;
  460.     int channel   = 0;
  461.     int occurence = 0;
  462.  
  463.     tlmBytes += bufsize;
  464.  
  465.     if (!CheckCRC(buffer, bufsize))
  466.     {
  467.         crcErrors++;
  468.         UpdateStatus();
  469.         return;
  470.     }
  471.  
  472.     timestamp = buffer[0] + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 24);
  473.     buffer  += 4;
  474.     bufsize -= 4;
  475.  
  476.     UpdateStatus();
  477.  
  478.     for (i = 0; i < (bufsize - 2); i += 2)
  479.     {
  480.         type  = (buffer[i + 1] & 0xF0) >> 4;
  481.         value = buffer[i] + ((buffer[i + 1] & 0x0F) << 8);
  482.  
  483.         switch (type)
  484.         {
  485.             case 2:
  486.                 channel   = value;
  487.                 occurence = 0;
  488.                 break;
  489.             case 1:
  490.                 FillTLM(value, channel, occurence);
  491.                 occurence++;
  492.                 break;
  493.             case 0:
  494.                 FillTLM(value, channel, occurence);
  495.                 occurence = 0;
  496.                 channel++;
  497.                 break;
  498.             default:
  499.                 break;
  500.         }
  501.     }
  502. }
  503.  
  504. /*
  505.  *    decode a received frame.
  506.  */
  507. void ProcessFrame(unsigned char *buffer, int bufsize)
  508. {
  509.     int n;
  510.     int via;
  511.     unsigned char protocol;
  512.     char toCall[10];
  513.     char fromCall[10];
  514.     char viaCall[10];
  515.  
  516.     /* check that frame is a kiss data frame */
  517.     /* ignore control frames - should not happen */
  518.     n = 0;
  519.  
  520.     if ((buffer[n] & 0x0F) == 0)
  521.     {
  522.         n++;
  523.  
  524.         /* decode the to/from address */
  525.         /* dont expect via address, but saves last if any */
  526.         via = ConvertCall(buffer + n, toCall);
  527.         n += 7;
  528.  
  529.         via = ConvertCall(buffer + n, fromCall);
  530.         n += 7;
  531.  
  532.         while (via)
  533.         {
  534.             via = ConvertCall(buffer + n, viaCall);
  535.             n += 7;
  536.         }
  537.  
  538.         /* check for a UI frame */
  539.         if ((buffer[n] & 0xEF) == 0003)
  540.         {
  541.             n++;
  542.             protocol = buffer[n++];
  543.  
  544.             /* see if the frame is a broadcast frame */    
  545.             if (protocol == PID_TEXT && strcmp(toCall, "TLM") == 0)
  546.             {
  547.                 DecodeTLM(buffer + n, bufsize - n);
  548.                 DrawTLMPage(current_page);
  549.                 if (fpraw != NULL)
  550.                 {
  551.                     fputc((bufsize - n) % 256, fpraw);
  552.                     fputc((bufsize - n) / 256, fpraw);
  553.                     fwrite(buffer + n, 1, bufsize - n, fpraw);
  554.                 }
  555.             }
  556.         }
  557.     }
  558. }
  559.  
  560. /*
  561.  *    callback function when a frame is received.
  562.  */
  563. void GetFrame(XtPointer closure, int *s, XtInputId *Id)
  564. {
  565.     unsigned char buffer[MAXBUFFER];
  566.     int bufsize;
  567.  
  568.     if ((bufsize = recv(s_raw, buffer, MAXBUFFER, 0)) == -1)
  569.     {
  570.         perror("recv");
  571.         return;
  572.     }
  573.  
  574.     ProcessFrame(buffer, bufsize);
  575. }
  576.  
  577. /*
  578.  *    the user wants to exit this program
  579.  */
  580. void QuitCb(Widget w, XtPointer client_data, XtPointer call_data)
  581. {
  582.     if (fpraw != NULL) fclose(fpraw);
  583.     if (s_raw != 0)    close(s_raw);
  584.  
  585.     XtDestroyApplicationContext(app_context);
  586.  
  587.     exit(0);
  588. }
  589.  
  590. void LogNextCb(Widget w, XtPointer client_data, XtPointer call_data)
  591. {
  592.     unsigned char buffer[300];
  593.     int bufsize;
  594.     Arg args[1];
  595.     time_t t;
  596.  
  597.     if (mode == ONLINE_MODE)
  598.     {
  599.         if (fpraw == NULL)
  600.         {
  601.             time(&t);
  602.             
  603.             sprintf(buffer, "%x.tlm", (int)t);
  604.             
  605.             if ((fpraw = fopen(buffer, "w")) == NULL)
  606.                 return;
  607.  
  608.             XtSetArg(args[0], XtNlabel, "TLM Log On");
  609.         }
  610.         else
  611.         {
  612.             fclose(fpraw);
  613.             fpraw = NULL;
  614.             XtSetArg(args[0], XtNlabel, "TLM Log Off");
  615.         }
  616.  
  617.         XtSetValues(lognextbutton, args, ONE);
  618.     }
  619.     else
  620.     {
  621.         if (!feof(fpraw))
  622.         {
  623.             bufsize = fgetc(fpraw);
  624.             bufsize += fgetc(fpraw) * 256;
  625.  
  626.             fread(buffer, 1, bufsize, fpraw);
  627.         
  628.             DecodeTLM(buffer, bufsize);
  629.             DrawTLMPage(current_page);
  630.         }
  631.     }
  632. }
  633.  
  634. void PageCb(Widget w, XtPointer client_data, XtPointer call_data)
  635. {
  636.     int page = (int)client_data;
  637.  
  638.     if (page != current_page)
  639.     {
  640.         DrawTLMPage(page);
  641.         UpdateStatus();
  642.     }
  643. }
  644.  
  645. void InsertChannel(struct equation *equation)
  646. {
  647.     struct equation *current;
  648.     
  649.     current = (struct equation *)XtMalloc(sizeof(struct equation));
  650.  
  651.     *current = *equation;
  652.  
  653.     if (first == NULL)
  654.     {
  655.         first = current;
  656.     }
  657.     else
  658.     {
  659.         equation = first;
  660.  
  661.         while (equation->next != NULL)
  662.             equation = equation->next;
  663.  
  664.         equation->next = current;
  665.     }
  666. }
  667.  
  668. int ReadConfig(void)
  669. {
  670.     char buffer[100];
  671.     char title[40], buf1[15], buf2[15];
  672.     FILE *fp;
  673.     struct equation current;
  674.     int page = 0, row = 0, column = 0;
  675.     int status = 0;
  676.     int count, i;
  677.  
  678.     if ((fp = fopen("tlm.cfg", "r")) == NULL)
  679.     {
  680.         fprintf(stderr, "Cannot open tlm.cfg\n");
  681.         return(-1);
  682.     }
  683.  
  684.     while (fgets(buffer, 100, fp) != NULL)
  685.     {
  686.         switch (*buffer)
  687.         {
  688.             case 'A':
  689.                 sscanf(buffer, "%*c %d , %[^,], %lf , %lf , %lf , %d ,",
  690.                     ¤t.channel, title, ¤t.a,
  691.                     ¤t.b, ¤t.c, &count);
  692.                 for (i = 0; i < count; i++)
  693.                 {
  694.                     current.next      = NULL;
  695.                     current.type      = *buffer;
  696.                     current.title     = XtNewString(title);
  697.                     current.occurence = i;
  698.                     current.page      = page;
  699.                     current.row       = row;
  700.                     current.column    = column;
  701.                     current.value     = -1;
  702.                     InsertChannel(¤t);
  703.                     column++;
  704.                     if (column > 2)
  705.                     {
  706.                         column = 0;
  707.                         row++;
  708.                     }
  709.                     if (row > 22)
  710.                     {
  711.                         column = 0;
  712.                         row    = 0;
  713.                         page++;
  714.                     }
  715.                 }
  716.                 break;
  717.             case 'D':
  718.                 sscanf(buffer, "%*c %d , %[^,], ",
  719.                     ¤t.channel, title);
  720.                 current.next      = NULL;
  721.                 current.type      = *buffer;
  722.                 current.status    = status;
  723.                 current.occurence = 0;
  724.                 current.title     = XtNewString(title);
  725.                 current.page      = page;
  726.                 current.row       = row;
  727.                 current.column    = column;
  728.                 current.value     = -1;
  729.                 InsertChannel(¤t);
  730.                 status += 12;
  731.                 column++;
  732.                 if (column > 2)
  733.                 {
  734.                     column = 0;
  735.                     row++;
  736.                 }
  737.                 if (row > 22)
  738.                 {
  739.                     column = 0;
  740.                     row    = 0;
  741.                     page++;
  742.                 }
  743.                 break;
  744.             case 'S':
  745.                 if (current.type != 'S')
  746.                 {
  747.                     page++;
  748.                     row    = 0;
  749.                     column = 0;
  750.                 }
  751.                 sscanf(buffer, "%*c %d , %49[^,], %14[^, ] , %14[^, \n]",
  752.                     ¤t.channel, title, buf1, buf2);
  753.                 current.next      = NULL;
  754.                 current.type      = *buffer;
  755.                 current.occurence = 0;
  756.                 current.title     = XtNewString(title);
  757.                 current.state0    = XtNewString(buf1);
  758.                 current.state1    = XtNewString(buf2);
  759.                 current.page      = page;
  760.                 current.row       = row;
  761.                 current.column    = column;
  762.                 current.value     = -1;
  763.                 InsertChannel(¤t);
  764.                 column++;
  765.                 if (column > 1)
  766.                 {
  767.                     column = 0;
  768.                     row++;
  769.                 }
  770.                 if (row > 22)
  771.                 {
  772.                     column = 0;
  773.                     row    = 0;
  774.                     page++;
  775.                 }
  776.                 break;
  777.             case '+':
  778.                 column += atoi(buffer + 1);
  779.                 while (column > 2)
  780.                 {
  781.                     column -= 3;
  782.                     row++;
  783.                 }
  784.                 if (row > 22)
  785.                 {
  786.                     column = 0;
  787.                     row    = 0;
  788.                     page++;
  789.                 }
  790.                 break;
  791.             default:
  792.                 break;
  793.         }
  794.     }
  795.     
  796.     fclose(fp);
  797.  
  798.     return(page + 1);
  799. }
  800.  
  801. int main(int argc, char **argv)
  802. {
  803.     static XtCallbackRec callback[2];
  804.     int i, pages;
  805.     char *s, title[80], name[10];
  806.  
  807.     if ((s = getenv("SATELLITE")) == NULL)
  808.     {
  809.         printf("SATELLITE environment variable not set.\n");
  810.         return(1);
  811.     }
  812.  
  813.     strcpy(satelliteId, s);
  814.  
  815.     if ((s = getenv("XTLM")) != NULL)
  816.     {
  817.         if ((fpraw = fopen(s, "r")) == NULL)
  818.         {
  819.             printf("Cannot open file %s\n", s);
  820.             return(1);
  821.         }
  822.  
  823.         mode = FILE_MODE;
  824.     }
  825.  
  826.     sprintf(title, "xtlm:%s %s", satelliteId, VERSION_STRING);
  827.  
  828.     strcat(satelliteId, "-0");
  829.  
  830.     if ((pages = ReadConfig()) == -1) return(1);
  831.  
  832.     toplevel = XtAppInitialize(&app_context, "Xpb", NULL, 0, &argc, argv,
  833.                 NULL, shell_args, XtNumber(shell_args));
  834.     XtVaSetValues(toplevel, XtNtitle, title, NULL);
  835.  
  836.     dpy  = XtDisplay(toplevel);
  837.  
  838.     XtGetApplicationResources(toplevel, &resources,
  839.                 resource_list, XtNumber(resource_list),
  840.                 NULL, ZERO);
  841.  
  842.     compwindow = XtCreateManagedWidget("appForm", formWidgetClass,
  843.                 toplevel, form_args, XtNumber(form_args));
  844.  
  845.     callback[0].callback = QuitCb;
  846.     callback[0].closure  = toplevel;
  847.     button_args[0].value = (XtArgVal)callback;
  848.     button_args[1].value = (XtArgVal)"Quit";
  849.     button_args[3].value = (XtArgVal)resources.button_font;
  850.     quitbutton = XtCreateManagedWidget("quitButton", commandWidgetClass,
  851.                 compwindow, button_args, XtNumber(button_args));
  852.  
  853.     callback[0].callback = LogNextCb;
  854.     callback[0].closure  = toplevel;
  855.     button_args[0].value = (XtArgVal)callback;
  856.     if (mode == ONLINE_MODE)
  857.         button_args[1].value = (XtArgVal)"TLM Log Off";
  858.     else
  859.         button_args[1].value = (XtArgVal)"Next";
  860.     button_args[2].value = (XtArgVal)quitbutton;
  861.     button_args[3].value = (XtArgVal)resources.button_font;
  862.     lognextbutton = XtCreateManagedWidget("lognextButton", commandWidgetClass,
  863.                 compwindow, button_args, XtNumber(button_args));
  864.  
  865.     for (i = 0; i < pages; i++)
  866.     {
  867.         sprintf(title, "Page %d", i);
  868.         sprintf(name,  "page%dButton",  i);
  869.     
  870.         callback[0].callback = PageCb;
  871.         callback[0].closure  = (XtPointer)i;
  872.         button_args[0].value = (XtArgVal)callback;
  873.         button_args[1].value = (XtArgVal)title;
  874.         if (i == 0)
  875.             button_args[2].value = (XtArgVal)lognextbutton;
  876.         else
  877.             button_args[2].value = (XtArgVal)button[i - 1];
  878.         button[i] = XtCreateManagedWidget(name, commandWidgetClass,
  879.                     compwindow, button_args, XtNumber(button_args));
  880.     }
  881.  
  882.     title_args[0].value = (XtArgVal)quitbutton;
  883.     title_args[2].value = (XtArgVal)resources.button_font;
  884.     pagelabel = XtCreateManagedWidget("pageLabel", labelWidgetClass,
  885.                 compwindow, title_args, XtNumber(title_args));
  886.  
  887.     title_args[1].value = (XtArgVal)pagelabel;
  888.     title_args[3].value = (XtArgVal)250;
  889.     timelabel = XtCreateManagedWidget("timeLabel", labelWidgetClass,
  890.                 compwindow, title_args, XtNumber(title_args));
  891.  
  892.     title_args[1].value = (XtArgVal)timelabel;
  893.     title_args[3].value = (XtArgVal)130;
  894.     tlmlabel = XtCreateManagedWidget("tlmLabel", labelWidgetClass,
  895.                 compwindow, title_args, XtNumber(title_args));
  896.  
  897.     title_args[1].value = (XtArgVal)tlmlabel;
  898.     crclabel = XtCreateManagedWidget("crcLabel", labelWidgetClass,
  899.                 compwindow, title_args, XtNumber(title_args));
  900.  
  901.     viewport_args[0].value = (XtArgVal)pagelabel;
  902.     viewport = XtCreateManagedWidget("tlmViewport", viewportWidgetClass,
  903.                 compwindow, viewport_args, XtNumber(viewport_args));
  904.  
  905.     form = XtCreateManagedWidget("tlmForm", formWidgetClass,
  906.                 viewport, form_args, XtNumber(form_args));
  907.  
  908.     for (i = 0; i < 23; i++)
  909.     {
  910.         sprintf(name,  "line%dLabel",  i);
  911.  
  912.         if (i > 0)
  913.             label_args[0].value = (XtArgVal)label[i - 1];
  914.         else
  915.             label_args[0].value = (XtArgVal)NULL;
  916.         label_args[1].value = (XtArgVal)resources.text_font;
  917.         label_args[4].value = (XtArgVal)600;
  918.         label[i] = XtCreateManagedWidget(name, labelWidgetClass,
  919.                 form, label_args, XtNumber(label_args));
  920.     }
  921.  
  922.     DrawTLMPage(0);
  923.     UpdateStatus();
  924.  
  925.     if (mode == ONLINE_MODE)
  926.     {
  927.         /* open up the raw socket to receive all packets */
  928.         if ((s_raw = socket(AF_INET, SOCK_PACKET, htons(2))) == -1)
  929.         {
  930.             perror("socket");
  931.             return(1);
  932.         }
  933.  
  934.         /* we want to be notified whenever a frame is received on the raw socket */
  935.         XtAppAddInput(app_context, s_raw, (XtPointer)XtInputReadMask, GetFrame, NULL);
  936.     }
  937.  
  938.     XtRealizeWidget(toplevel);
  939.  
  940.     XtAppMainLoop(app_context);
  941.     
  942.     return(0);
  943. }
  944.  
  945.